use derive_builder::Builder;
use serde::{Deserialize, Serialize};
use serde_json::Value;
use std::collections::HashMap;

use crate::{
    assistant::prompts::PromptTemplateItem,
    datasource::{QueryCondition, QueryExtention},
    error::Error,
    modeling::{ComparsionOperator, LogicalOperator, ValueType},
};

use super::{
    DataOperatorMethod, PromptSpeechFile, PromptSpeechSelector, PromptSpeechTemplate,
    PromptSpeechType, ValueSelector, WorkflowErrorHandleMode, WorkflowErrorStrategy, WorkflowHost,
    WorkflowHttpAuthorization, WorkflowHttpBody, WorkflowHttpMethod, WorkflowHttpRequestTimeout,
    WorkflowListExtract, WorkflowListFilter, WorkflowListLimit, WorkflowListOrder, WorkflowModel,
    WorkflowScriptLanguage, WorkflowTTSOptions,
};

#[derive(Debug, Serialize, Deserialize, Clone, PartialEq)]
pub struct WorkflowDocument {
    #[serde(rename = "graph")]
    pub graph: WorkflowGraph,
    #[serde(rename = "features")]
    pub features: WorkflowFeature,
    #[serde(rename = "environment_variables")]
    pub environment_variables: Vec<WorkflowVariable>,
    #[serde(rename = "conversation_variables")]
    pub conversation_variables: Vec<WorkflowVariable>,
}

#[derive(Debug, Serialize, Deserialize, Clone, PartialEq)]
pub struct WorkflowGraph {
    #[serde(rename = "nodes")]
    pub nodes: Vec<WorkflowGraphNode>,
    #[serde(rename = "edges")]
    pub edges: Vec<WorkflowGraphEdge>,
}

#[derive(Debug, Serialize, Deserialize, Default, Clone, Builder, PartialEq)]
#[builder(name = "WorkflowGraphNodeBuilder")]
#[builder(pattern = "mutable")]
#[builder(setter(into, strip_option), default)]
#[builder(derive(Debug))]
#[builder(build_fn(error = "Error"))]
pub struct WorkflowGraphNode {
    #[serde(rename = "id")]
    pub id: String,
    #[serde(rename = "type")]
    pub r#type: String,
    #[serde(rename = "data")]
    pub data: WorkflowGraphNodeData,
    #[serde(rename = "parentId")]
    pub parent_id: Option<String>,
}

pub type WorkflowGraphNodeRef = Box<WorkflowGraphNode>;

#[derive(Debug, Serialize, Deserialize, Clone, PartialEq)]
#[serde(tag = "type")]
pub enum WorkflowGraphNodeData {
    #[serde(rename = "start")]
    Start(WorkflowGraphNodeStart),
    #[serde(rename = "if-else")]
    IfElse(WorkflowGraphNodeIfElse),
    #[serde(rename = "code")]
    Code(WorkflowGraphNodeCode),
    #[serde(rename = "iteration")]
    Iteration(WorkflowGraphNodeIteration),
    #[serde(rename = "iteration-start")]
    IterationStart(WorkflowGraphNodeIterationStart),
    #[serde(rename = "http-request")]
    HttpRequest(WorkflowGraphNodeHttpStatement),
    #[serde(rename = "html-extractor")]
    HtmlExtractor(WorkflowGraphNodeHtmlExtractorStatement),
    #[serde(rename = "document-extractor")]
    DocumentExtractor(WorkflowGraphNodeDocumentExtractorStatement),
    #[serde(rename = "variable-aggregator")]
    VariableAggregator(WorkflowGraphNodeVariableAggregatorStatement),
    #[serde(rename = "list-operator")]
    ListOperator(WorkflowGraphNodeListOperatorStatement),
    #[serde(rename = "meta-operator")]
    MetaOperator(WorkflowGraphNodeMetaOperatorStatement),
    #[serde(rename = "data-operator")]
    DataOperator(WorkflowGraphNodeDataOperatorStatement),
    #[serde(rename = "sql-operator")]
    SQLOperator(WorkflowGraphNodeSqlStatement),
    #[serde(rename = "llm")]
    LLM(WorkflowGraphNodeLlmStatement),
    #[serde(rename = "speech-generator")]
    SpeechGenerator(WorkflowGraphNodeSpeechGeneratorStatement),
    #[serde(rename = "image-generator")]
    ImageGenerator(WorkflowGraphNodeImageGeneratorStatement),
    #[serde(rename = "video-generator")]
    VideoGenerator(WorkflowGraphNodeVideoGeneratorStatement),
    #[serde(rename = "wait")]
    Wait(WorkflowGraphNodeWaitStatement),
    #[serde(rename = "wasm")]
    Wasm(WorkflowGraphNodeWasmStatement),
    #[serde(rename = "cli")]
    CLI(WorkflowGraphNodeCli),
    #[serde(rename = "tool")]
    Tool(WorkflowGraphNodeToolStatement),
    #[serde(rename = "statement")]
    Statement(WorkflowGraphNodeStatement),
    #[serde(rename = "end")]
    End(WorkflowGraphNodeEnd),
}

impl Default for WorkflowGraphNodeData {
    fn default() -> Self {
        Self::End(WorkflowGraphNodeEnd::default())
    }
}

#[derive(Debug, Default, Serialize, Deserialize, Clone, PartialEq)]
pub struct WorkflowGraphNodeStart {
    pub variables: Vec<WorkflowVariable>,
}

#[derive(Debug, Serialize, Deserialize, Default, Clone, Builder, PartialEq)]
#[builder(name = "WorkflowGraphNodeIfElseBuilder")]
#[builder(pattern = "mutable")]
#[builder(setter(into, strip_option), default)]
#[builder(derive(Debug))]
#[builder(build_fn(error = "Error"))]
pub struct WorkflowGraphNodeIfElse {
    pub cases: Vec<WorkflowCase>,
}

#[derive(Debug, Serialize, Deserialize, Default, Clone, Builder, PartialEq)]
#[builder(name = "WorkflowGraphNodeWaitStatementBuilder")]
#[builder(pattern = "mutable")]
#[builder(setter(into, strip_option), default)]
#[builder(derive(Debug))]
#[builder(build_fn(error = "Error"))]
pub struct WorkflowGraphNodeWaitStatement {
    pub cases: Option<WorkflowCase>,
    pub timeout: Option<u32>,
    pub interval: Option<u32>,
}

#[derive(Debug, Serialize, Deserialize, Default, Clone, Builder, PartialEq)]
#[builder(name = "WorkflowGraphNodeOutputItemBuilder")]
#[builder(pattern = "mutable")]
#[builder(setter(into, strip_option), default)]
#[builder(derive(Debug))]
#[builder(build_fn(error = "Error"))]
pub struct WorkflowGraphNodeOutputItem {
    pub r#type: String,
    pub children: Option<serde_json::Value>,
}

#[derive(Debug, Serialize, Deserialize, Default, Clone, Builder, PartialEq)]
#[builder(name = "WorkflowGraphNodeCodeBuilder")]
#[builder(pattern = "mutable")]
#[builder(setter(into, strip_option), default)]
#[builder(derive(Debug))]
#[builder(build_fn(error = "Error"))]
pub struct WorkflowGraphNodeCode {
    pub variables: Vec<WorkflowInputVariable>,
    pub code_language: WorkflowScriptLanguage,
    pub code: String,
    pub outputs: HashMap<String, WorkflowGraphNodeOutputItem>,
    pub error_strategy: Option<WorkflowErrorStrategy>,
}

#[derive(Debug, Serialize, Deserialize, Default, Clone, Builder, PartialEq)]
#[builder(name = "WorkflowGraphNodeCliBuilder")]
#[builder(pattern = "mutable")]
#[builder(setter(into, strip_option), default)]
#[builder(derive(Debug))]
#[builder(build_fn(error = "Error"))]
pub struct WorkflowGraphNodeCli {
    pub variables: Vec<WorkflowInputVariable>,
    pub host: Option<WorkflowHost>,
    pub command: String,
    pub arguments: Vec<String>,
    pub outputs: HashMap<String, WorkflowGraphNodeOutputItem>,
    pub error_strategy: Option<WorkflowErrorStrategy>,
}

#[derive(Debug, Serialize, Deserialize, Clone, PartialEq)]
pub struct WorkflowGraphNodeIteration {
    pub start_node_id: String,
    pub iterator_selector: Vec<String>,
    pub output_selector: ValueSelector,
    pub is_parallel: bool,
    pub parallel_nums: u32,
    pub output_type: Option<String>,
    pub error_handle_mode: WorkflowErrorHandleMode,
}

#[derive(Debug, Serialize, Deserialize, Clone, PartialEq)]
pub struct WorkflowGraphNodeIterationStart {}

#[derive(Debug, Serialize, Deserialize, Clone, PartialEq)]
#[serde(tag = "statement")]
pub enum WorkflowGraphNodeStatement {
    #[serde(rename = "trycatch")]
    TryCatch(WorkflowGraphNodeTryCatch),
    #[serde(rename = "http")]
    Http(WorkflowGraphNodeHttpStatement),
    #[serde(rename = "llm")]
    LLM(WorkflowGraphNodeLlmStatement),
}

#[derive(Debug, Serialize, Deserialize, Clone, PartialEq)]
pub struct WorkflowGraphNodeHttpStatement {
    pub url: String,
    pub method: WorkflowHttpMethod,
    pub authorization: WorkflowHttpAuthorization,
    pub headers: Option<String>,
    pub params: Option<String>,
    pub body: WorkflowHttpBody,
    pub timeout: Option<WorkflowHttpRequestTimeout>,
    pub error_strategy: Option<WorkflowErrorStrategy>,
}

#[derive(Debug, Serialize, Deserialize, Default, Clone, Builder, PartialEq)]
#[builder(name = "WorkflowGraphNodeListOperatorStatementBuilder")]
#[builder(pattern = "mutable")]
#[builder(setter(into, strip_option), default)]
#[builder(derive(Debug))]
#[builder(build_fn(error = "Error"))]
pub struct WorkflowGraphNodeListOperatorStatement {
    pub variable: ValueSelector,
    pub filter_by: WorkflowListFilter,
    pub extract_by: WorkflowListExtract,
    pub order_by: WorkflowListOrder,
    pub limit: WorkflowListLimit,
    pub var_type: String,
    pub item_var_type: String,
    pub error_strategy: Option<WorkflowErrorStrategy>,
}

#[derive(Debug, Serialize, Deserialize, Default, Clone, Builder, PartialEq)]
#[builder(name = "WorkflowGraphNodeHtmlExtractorStatementBuilder")]
#[builder(pattern = "mutable")]
#[builder(setter(into, strip_option), default)]
#[builder(derive(Debug))]
#[builder(build_fn(error = "Error"))]
pub struct WorkflowGraphNodeHtmlExtractorStatement {
    pub url: String,
    pub selector: String,
    pub attribute: Option<String>,
    pub text: Option<bool>,
    pub timeout: Option<WorkflowHttpRequestTimeout>,
    pub outputs: HashMap<String, WorkflowGraphNodeOutputItem>,
    pub error_strategy: Option<WorkflowErrorStrategy>,
}

#[derive(Debug, Serialize, Deserialize, Default, Clone, Builder, PartialEq)]
#[builder(name = "WorkflowGraphNodeDocumentExtractorStatementBuilder")]
#[builder(pattern = "mutable")]
#[builder(setter(into, strip_option), default)]
#[builder(derive(Debug))]
#[builder(build_fn(error = "Error"))]
pub struct WorkflowGraphNodeDocumentExtractorStatement {
    pub variable_selector: ValueSelector,
    pub is_array_file: Option<bool>,
    pub error_strategy: Option<WorkflowErrorStrategy>,
}

#[derive(Debug, Serialize, Deserialize, Default, Clone, Builder, PartialEq)]
#[builder(name = "WorkflowGraphNodeVariableAggregatorStatementBuilder")]
#[builder(pattern = "mutable")]
#[builder(setter(into, strip_option), default)]
#[builder(derive(Debug))]
#[builder(build_fn(error = "Error"))]
pub struct WorkflowGraphNodeVariableAggregatorStatement {
    pub variables: Vec<ValueSelector>,
    pub advanced_settings: VariableAggregatorAdvancedSettings,
    pub output_type: String,
    pub error_strategy: Option<WorkflowErrorStrategy>,
}

#[derive(Debug, Serialize, Deserialize, Default, Clone, Builder, PartialEq)]
#[builder(name = "VariableAggregatorAdvancedSettingsBuilder")]
#[builder(pattern = "mutable")]
#[builder(setter(into, strip_option), default)]
#[builder(derive(Debug))]
#[builder(build_fn(error = "Error"))]
pub struct VariableAggregatorAdvancedSettings {
    pub group_enabled: bool,
    pub groups: Vec<VariableAggregatorGroup>,
}

#[derive(Debug, Serialize, Deserialize, Default, Clone, Builder, PartialEq)]
#[builder(name = "VariableAggregatorGroupBuilder")]
#[builder(pattern = "mutable")]
#[builder(setter(into, strip_option), default)]
#[builder(derive(Debug))]
#[builder(build_fn(error = "Error"))]
pub struct VariableAggregatorGroup {
    pub output_type: String,
    pub variables: Vec<ValueSelector>,
}

#[derive(Debug, Serialize, Deserialize, Default, Clone, Builder, PartialEq)]
#[builder(name = "WorkflowGraphNodeWasmStatementBuilder")]
#[builder(pattern = "mutable")]
#[builder(setter(into, strip_option), default)]
#[builder(derive(Debug))]
#[builder(build_fn(error = "Error"))]
pub struct WorkflowGraphNodeWasmStatement {
    pub file: String,
    pub function_name: String,
    pub arguments: Option<String>,
    pub timeout: Option<WorkflowHttpRequestTimeout>,
    pub outputs: HashMap<String, WorkflowGraphNodeOutputItem>,
    pub error_strategy: Option<WorkflowErrorStrategy>,
}

#[derive(Debug, Serialize, Deserialize, Default, Clone, Builder, PartialEq)]
#[builder(name = "WorkflowGraphNodeToolStatementBuilder")]
#[builder(pattern = "mutable")]
#[builder(setter(into, strip_option), default)]
#[builder(derive(Debug))]
#[builder(build_fn(error = "Error"))]
pub struct WorkflowGraphNodeToolStatement {
    pub tool_parameters: String,
    pub tool_configurations: String,
    pub provider_id: String,
    pub provider_type: String,
    pub provider_name: Option<String>,
    pub tool_name: String,
    pub tool_label: Option<String>,
    pub timeout: Option<WorkflowHttpRequestTimeout>,
    pub outputs: HashMap<String, WorkflowGraphNodeOutputItem>,
    pub error_strategy: Option<WorkflowErrorStrategy>,
}

#[derive(Debug, Serialize, Deserialize, Default, Clone, Builder, PartialEq)]
#[builder(name = "WorkflowGraphNodeMetaOperatorStatementBuilder")]
#[builder(pattern = "mutable")]
#[builder(setter(into, strip_option), default)]
#[builder(derive(Debug))]
#[builder(build_fn(error = "Error"))]
pub struct WorkflowGraphNodeMetaOperatorStatement {
    pub class_type: String,
    pub identifier: String,
    pub method: String,
    pub outputs: HashMap<String, WorkflowGraphNodeOutputItem>,
    pub error_strategy: Option<WorkflowErrorStrategy>,
}

#[derive(Debug, Serialize, Deserialize, Default, Clone, Builder, PartialEq)]
#[builder(name = "WorkflowGraphNodeDataOperatorStatementBuilder")]
#[builder(pattern = "mutable")]
#[builder(setter(into, strip_option), default)]
#[builder(derive(Debug))]
#[builder(build_fn(error = "Error"))]
pub struct WorkflowGraphNodeDataOperatorStatement {
    pub domain: String,
    pub class: String,
    pub method: DataOperatorMethod,
    pub datasource: Option<String>,
    pub conditions: Option<QueryCondition>,
    pub extentions: Option<QueryExtention>,
    pub value: Option<HashMap<String, serde_json::Value>>,
    pub options: Option<HashMap<String, serde_json::Value>>,
    pub outputs: HashMap<String, WorkflowGraphNodeOutputItem>,
    pub error_strategy: Option<WorkflowErrorStrategy>,
}

#[derive(Debug, Serialize, Deserialize, Default, Clone, Builder, PartialEq)]
#[builder(name = "WorkflowGraphNodeSqlStatementBuilder")]
#[builder(pattern = "mutable")]
#[builder(setter(into, strip_option), default)]
#[builder(derive(Debug))]
#[builder(build_fn(error = "Error"))]
pub struct WorkflowGraphNodeSqlStatement {
    pub variables: Vec<WorkflowInputVariable>,
    pub script: String,
    pub is_query: bool,
    pub datasource: Vec<String>,
    pub outputs: HashMap<String, WorkflowGraphNodeOutputItem>,
    pub error_strategy: Option<WorkflowErrorStrategy>,
}

#[derive(Debug, Serialize, Deserialize, Default, Clone, Builder, PartialEq)]
#[builder(name = "WorkflowGraphNodeLlmStatementBuilder")]
#[builder(pattern = "mutable")]
#[builder(setter(into, strip_option), default)]
#[builder(derive(Debug))]
#[builder(build_fn(error = "Error"))]
pub struct WorkflowGraphNodeLlmStatement {
    pub model: WorkflowModel,
    pub prompt_template: Vec<PromptTemplateItem>,
}

#[derive(Debug, Serialize, Deserialize, Default, Clone, Builder, PartialEq)]
#[builder(name = "WorkflowGraphNodeSpeechGeneratorStatementBuilder")]
#[builder(pattern = "mutable")]
#[builder(setter(into, strip_option), default)]
#[builder(derive(Debug))]
#[builder(build_fn(error = "Error"))]
pub struct WorkflowGraphNodeSpeechGeneratorStatement {
    pub model: WorkflowModel,
    pub prompt_speech_type: PromptSpeechType,
    pub prompt_speech_selector: Option<PromptSpeechSelector>,
    pub prompt_speech_template: Option<PromptSpeechTemplate>,
    pub prompt_speech: Option<PromptSpeechFile>,
    pub text: String,
    pub options: serde_json::Value,
    pub error_strategy: Option<WorkflowErrorStrategy>,
}

#[derive(Debug, Serialize, Deserialize, Default, Clone, Builder, PartialEq)]
#[builder(name = "WorkflowGraphNodeVideoGeneratorStatementBuilder")]
#[builder(pattern = "mutable")]
#[builder(setter(into, strip_option), default)]
#[builder(derive(Debug))]
#[builder(build_fn(error = "Error"))]
pub struct WorkflowGraphNodeVideoGeneratorStatement {
    pub model: WorkflowModel,
    pub prompt_text: String,
    pub prompt_speech: String,
    pub text: String,
    pub options: serde_json::Value,
    pub error_strategy: Option<WorkflowErrorStrategy>,
}

#[derive(Debug, Serialize, Deserialize, Default, Clone, Builder, PartialEq)]
#[builder(name = "WorkflowGraphNodeImageGeneratorStatementBuilder")]
#[builder(pattern = "mutable")]
#[builder(setter(into, strip_option), default)]
#[builder(derive(Debug))]
#[builder(build_fn(error = "Error"))]
pub struct WorkflowGraphNodeImageGeneratorStatement {
    pub model: WorkflowModel,
    pub prompt_text: String,
    pub prompt_speech: String,
    pub text: String,
    pub options: serde_json::Value,
    pub error_strategy: Option<WorkflowErrorStrategy>,
}

#[derive(Debug, Serialize, Deserialize, Clone, PartialEq)]
pub struct WorkflowGraphNodeTryCatch {}

#[derive(Debug, Default, Serialize, Deserialize, Clone, PartialEq)]
pub struct WorkflowGraphNodeEnd {
    pub outputs: Vec<WorkflowOutputVariable>,
}

#[derive(Debug, Serialize, Deserialize, Default, Clone, Builder, PartialEq)]
#[builder(name = "WorkflowGraphEdgeBuilder")]
#[builder(pattern = "mutable")]
#[builder(setter(into, strip_option), default)]
#[builder(derive(Debug))]
#[builder(build_fn(error = "Error"))]
pub struct WorkflowGraphEdge {
    pub id: String,
    pub source: String,
    #[serde(rename = "sourceHandle")]
    pub source_handle: String,
    pub target: String,
    #[serde(rename = "targetHandle")]
    pub target_handle: String,
}

#[derive(Debug, Default, Serialize, Deserialize, Clone, PartialEq)]
pub struct WorkflowFeature {}

#[derive(Debug, Default, Serialize, Deserialize, Clone, PartialEq)]
pub struct WorkflowVariable {
    pub variable: String,
    pub label: Option<String>,
    pub r#type: String,
    pub max_length: Option<u32>,
    pub required: bool,
    pub options: Vec<Value>,
}

#[derive(Debug, Default, Serialize, Deserialize, Clone, PartialEq)]
pub struct WorkflowCase {
    pub logical_operator: LogicalOperator,
    pub case_id: String,
    pub conditions: Vec<WorkflowCondition>,
}

#[derive(Debug, Default, Serialize, Deserialize, Clone, PartialEq)]
pub struct WorkflowCondition {
    #[serde(rename = "id")]
    pub id: String,
    #[serde(rename = "varType")]
    pub var_type: String,
    #[serde(rename = "variable_selector")]
    pub variable_selector: (String, String),
    #[serde(rename = "comparsion_operator")]
    pub comparsion_operator: ComparsionOperator,
    #[serde(rename = "value")]
    pub value: String,
}

#[derive(Debug, Default, Serialize, Deserialize, Clone, PartialEq)]
pub struct WorkflowOutputVariable {
    pub variable: String,
    pub value_selector: (String, String),
}

#[derive(Debug, Default, Serialize, Deserialize, Clone, PartialEq)]
pub struct WorkflowInputVariable {
    pub variable: String,
    pub value_selector: (String, String),
}

#[derive(Debug, Default, Serialize, Deserialize, Clone, PartialEq)]
pub enum WorkflowResultStatus {
    #[default]
    #[serde(rename = "succeeded")]
    Succeeded,
    #[serde(rename = "failed")]
    Failed,
}

#[derive(Debug, Serialize, Deserialize, Default, Clone, Builder, PartialEq)]
#[builder(name = "WorkflowResultBuilder")]
#[builder(pattern = "mutable")]
#[builder(setter(into, strip_option), default)]
#[builder(derive(Debug))]
#[builder(build_fn(error = "Error"))]
pub struct WorkflowResult {
    pub status: WorkflowResultStatus,
    pub outputs: HashMap<String, serde_json::Value>,
    pub files: Vec<String>,
    pub created_at: i64,
    pub finished_at: i64,
}

unsafe impl Send for WorkflowResult {}

impl WorkflowResult {
    pub fn with_failed() -> Self {
        Self {
            status: WorkflowResultStatus::Failed,
            ..Default::default()
        }
    }
}

//
#[derive(Debug, Default, Serialize, Deserialize, Clone, PartialEq)]
pub struct WorkflowDocumentReadeOptions {}

#[async_trait::async_trait]
pub trait WorkflowDocumentReader {
    /// 读取document
    async fn read_from_json_file(
        &self,
        json: &String,
        options: WorkflowDocumentReadeOptions,
    ) -> anyhow::Result<WorkflowDocument>;

    async fn read_from_string(
        &self,
        json_string: &String,
        options: WorkflowDocumentReadeOptions,
    ) -> anyhow::Result<WorkflowDocument>;
}

impl TryInto<ValueType> for WorkflowGraphNodeOutputItem {
    type Error = anyhow::Error;
    fn try_into(self) -> Result<ValueType, Self::Error> {
        ValueType::try_from_string(&self.r#type)
    }
}

impl WorkflowGraphNode {
    ///
    pub fn is_iteration(&self) -> bool {
        match &self.data {
            WorkflowGraphNodeData::Iteration(_) => true,
            _ => false,
        }
    }
    ///
    pub fn iteration_start_id(&self) -> Option<String> {
        match &self.data {
            WorkflowGraphNodeData::Iteration(v) => Some(v.start_node_id.clone()),
            _ => None,
        }
    }
}
